import { Injectable } from '@nestjs/common';
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { ToolsService } from 'src/utils/tools.service';
import { DataSource, Repository } from 'typeorm';
import { CreateRoleDto } from './dto/create-role.dto';
import { PaginationDto } from 'src/common/dto/pagination.dto';
import { UpdateRoleDto } from './dto/update-role.dto';
import { RoleEntity } from './entities/role.entity';
import { AddAccessDto } from './dto/add-access.dto';
import { AccessEntity } from '../access/entities/access.entity';

@Injectable()
export class RoleService {
  @InjectRepository(RoleEntity)
  private readonly rolesRepository: Repository<RoleEntity>;
  @InjectDataSource()
  private readonly dataSource: DataSource;

  async create(createRoleDto: CreateRoleDto) {
    const queryRunner = this.dataSource.createQueryRunner();
    try {
      const manager = await queryRunner.manager; //使用事务
      const role = new RoleEntity();
      role.rolename = createRoleDto.rolename;
      await manager.save(role);
      return role;
    } catch (error) {
      ToolsService.fail(error);
    }
  }

  async findAll(rolename: string, pagination: PaginationDto) {
    try {
      const res = await this.rolesRepository
        .createQueryBuilder('role')
        .where('role.rolename LIKE :param')
        .setParameters({
          param: '%' + rolename + '%',
        })
        .offset(pagination.currentPage * pagination.pageSize)
        .limit(pagination.pageSize)
        .orderBy('role.created_at', 'DESC') //DESC ASC
        .getManyAndCount();
      return res;
    } catch (error) {
      ToolsService.fail(error);
    }
  }

  findOne(id: number) {
    return `This action returns a #${id} role`;
  }

  async update(id: string, updateRoleDto: UpdateRoleDto) {
    const queryRunner = this.dataSource.createQueryRunner();
    try {
      const manager = await queryRunner.manager; //使用事务
      const role = new RoleEntity();
      role.id = id;
      role.rolename = updateRoleDto.rolename;
      await manager.save(role);
      return role;
    } catch (error) {
      ToolsService.fail(error);
    }
  }

  async remove(id: string) {
    try {
      await this.rolesRepository
        .createQueryBuilder()
        .delete()
        .from(RoleEntity)
        .where('id = :id', { id: id })
        .execute();
    } catch (error) {
      ToolsService.fail(error);
    }
  }

  async addAccess(addAccessDto: AddAccessDto) {
    const queryRunner = this.dataSource.createQueryRunner();
    try {
      const manager = await queryRunner.manager; //使用事务
      const role = await manager
        .getRepository(RoleEntity)
        .createQueryBuilder('role')
        .where('role.id = :id', {
          id: addAccessDto.roleId,
        })
        .getOne();
      if (!role) {
        throw new Error('角色不存在');
      }
      if (addAccessDto.accessIds.length > 0) {
        const access = [];
        for (let i = 0; i < addAccessDto.accessIds.length; i++) {
          const listOne = await manager
            .getRepository(AccessEntity)
            .createQueryBuilder('access')
            .where('access.id = :id', {
              id: addAccessDto.accessIds[i],
            })
            .getOne();
          if (!listOne) ToolsService.fail('权限id不存在');
          access.push(listOne);
        }
        const roleEntity = new RoleEntity();
        roleEntity.id = addAccessDto.roleId;
        roleEntity.access = access;
        await manager.save(roleEntity);
      } else {
        const roleEntity = new RoleEntity();
        roleEntity.id = addAccessDto.roleId;
        roleEntity.access = [];
        await manager.save(roleEntity);
      }
      return '添加成功';
    } catch (error) {
      ToolsService.fail(error);
    }
  }

  async findOwnerAccess(roleId: string) {
    try {
      const role = await this.rolesRepository
        .createQueryBuilder('role')
        .where('role.id = :id', { id: roleId })
        .leftJoinAndSelect('role.access', 'access')
        .select(['role', 'access'])
        .getOneOrFail();
      return role.access;
    } catch (error) {
      ToolsService.fail(error);
    }
  }
}
